#include <math.h>
#include "game.h"

static float base_speed(Ghost* ghost, Game* game) {
    return LEVEL_SPECS[game->level_index].ghost_speed;
}

////////////
// BLINKY //
////////////

static int blinky_aggression_level(GhostAI* ai, Game* game) {
    // if this is a retry run, blinky will not go aggro
    // until clyde leaves the house
    // TODO: what if clyde re-enters the house after being eaten?
    if (game->is_retry && game->ghosts[3].in_house)
        return 0;

    if (game->dots_left <= 10)
        return 2;

    if (game->dots_left <= 20)
        return 1;

    return 0;
}

static void blinky_recalculate_goal(Ghost* ghost, Game* game) {
    GhostAI* ai = &ghost->ai;

    if (ghost->scatter && blinky_aggression_level(ai, game) == 0) {
        ai->target_x = ai->scatter_x;
        ai->target_y = ai->scatter_y;
        return;
    }

    ai->target_x = game->player.x / 8;
    ai->target_y = game->player.y / 8;
}

static float blinky_base_speed(Ghost* ghost, Game* game) {
    GhostAI* ai = &ghost->ai;

    int aggression = blinky_aggression_level(ai, game);

    if (aggression == 2)
        return LEVEL_SPECS[game->level_index].elroy2_speed;

    if (aggression == 1)
        return LEVEL_SPECS[game->level_index].elroy1_speed;

    return base_speed(ghost, game);
}

static int blinky_is_dot_tracker_reached(int level_index, int dot_count) {
    return TRUE;
}

static int blinky_is_global_dot_tracker_reached(int level_index, int dot_count) {
    return TRUE;
}

void ghost_ai_blinky(GhostAI* ai) {
    ai->scatter_x = 25;
    ai->scatter_y = 0;
    ai->home_x = 14;
    ai->palette = 1;

    ai->recalculate_goal = blinky_recalculate_goal;
    ai->base_speed = blinky_base_speed;
    ai->is_dot_tracker_reached = blinky_is_dot_tracker_reached;
    ai->is_global_dot_tracker_reached = blinky_is_global_dot_tracker_reached;
}

///////////
// PINKY //
///////////

static void pinky_recalculate_goal(Ghost* ghost, Game* game) {
    GhostAI* ai = &ghost->ai;

    if (ghost->scatter) {
        ai->target_x = ai->scatter_x;
        ai->target_y = ai->scatter_y;
        return;
    }

    ai->target_x = obj_cell_x(&game->player) + game->player.dx * 4;
    ai->target_y = obj_cell_y(&game->player) + game->player.dy * 4;

    // bug emulation
    if (game->player.dy == -1)
        ai->target_x -= 4;
}

static int pinky_is_dot_tracker_reached(int level_index, int dot_count) {
    return TRUE;
}

static int pinky_is_global_dot_tracker_reached(int level_index, int dot_count) {
    return dot_count == 7;
}

void ghost_ai_pinky(GhostAI* ai) {
    ai->scatter_x = 2;
    ai->scatter_y = 0;
    ai->home_x = 14;
    ai->palette = 3;

    ai->recalculate_goal = pinky_recalculate_goal;
    ai->base_speed = base_speed;
    ai->is_dot_tracker_reached = pinky_is_dot_tracker_reached;
    ai->is_global_dot_tracker_reached = pinky_is_global_dot_tracker_reached;
}

//////////
// INKY //
//////////

static void inky_recalculate_goal(Ghost* ghost, Game* game) {
    GhostAI* ai = &ghost->ai;

    if (ghost->scatter) {
        ai->target_x = ai->scatter_x;
        ai->target_y = ai->scatter_y;
        return;
    }

    // two tiles in "front" of pac-man
    int cx = obj_cell_x(&game->player) + game->player.dx * 2;
    int cy = obj_cell_y(&game->player) + game->player.dy * 2;
    if (game->player.dy == -1) // bug emulation
        cx -= 2;

    // also dependent on blinky's position
    ai->target_x = (cx - obj_cell_x(&game->ghosts[0])) * 2 + obj_cell_x(&game->ghosts[0]);
    ai->target_y = (cy - obj_cell_y(&game->ghosts[0])) * 2 + obj_cell_y(&game->ghosts[1]);
}

static int inky_is_dot_tracker_reached(int level_index, int dot_count) {
    if (level_index >= 1) return TRUE;
    return dot_count >= 30;
}

static int inky_is_global_dot_tracker_reached(int level_index, int dot_count) {
    return dot_count == 17;
}

void ghost_ai_inky(GhostAI* ai) {
    ai->scatter_x = 27;
    ai->scatter_y = 34;
    ai->home_x = 12;
    ai->palette = 5;

    ai->recalculate_goal = inky_recalculate_goal;
    ai->base_speed = base_speed;
    ai->is_dot_tracker_reached = inky_is_dot_tracker_reached;
    ai->is_global_dot_tracker_reached = inky_is_global_dot_tracker_reached;
}

///////////
// CLYDE //
///////////

static void clyde_recalculate_goal(Ghost* ghost, Game* game) {
    GhostAI* ai = &ghost->ai;

    if (ghost->scatter) {
        ai->target_x = ai->scatter_x;
        ai->target_y = ai->scatter_y;
        return;
    }
    
    float dx = (float)(obj_cell_x(&game->player) - obj_cell_x(ghost));
    float dy = (float)(obj_cell_y(&game->player) - obj_cell_y(ghost));
    float dist = sqrtf(dx*dx + dy*dy);

    if (dist >= 8) {
        ai->target_x = obj_cell_x(&game->player);
        ai->target_y = obj_cell_y(&game->player);
    } else {
        ai->target_x = ai->scatter_x;
        ai->target_y = ai->scatter_y;
    }
}

static int clyde_is_dot_tracker_reached(int level_index, int dot_count) {
    if (level_index >= 2) return TRUE;
    if (level_index >= 1) return dot_count >= 50;
    return dot_count >= 60;
}

static int clyde_is_global_dot_tracker_reached(int level_index, int dot_count) {
    return FALSE;
}

void ghost_ai_clyde(GhostAI* ai) {
    ai->scatter_x = 0;
    ai->scatter_y = 34;
    ai->home_x = 16;
    ai->palette = 7;

    ai->recalculate_goal = clyde_recalculate_goal;
    ai->base_speed = base_speed;
    ai->is_dot_tracker_reached = clyde_is_dot_tracker_reached;
    ai->is_global_dot_tracker_reached = clyde_is_global_dot_tracker_reached;
}